package com.linsen.core.redis.config;

import com.alibaba.fastjson.support.spring.GenericFastJsonRedisSerializer;
import com.linsen.core.common.annotation.AutoConfiguration;
import com.linsen.core.common.model.LimitMeta;
import com.linsen.core.common.model.User;
import com.linsen.core.redis.aspect.RequestLimitAspect;
import com.linsen.core.redis.props.LinsenRedisProperties;
import com.linsen.core.redis.service.RedisService;
import com.linsen.core.redis.util.RedisLockUtil;
import com.linsen.core.redis.util.RedisSecurityUtil;
import com.linsen.core.redis.util.RedisUtil;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.listener.RedisMessageListenerContainer;
import org.springframework.data.redis.serializer.GenericToStringSerializer;

import java.util.List;

/**
 * Redis基础配置类
 *
 * @author zhaoyong
 * @date 2023/3/11
 */
@AutoConfiguration
@EnableConfigurationProperties({LinsenRedisProperties.class})
public class LinsenRedisAutoConfiguration {
    @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
        RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
        redisTemplate.setConnectionFactory(redisConnectionFactory);
        // 使用 GenericFastJsonRedisSerializer 替换默认序列化
        GenericFastJsonRedisSerializer genericFastJsonRedisSerializer = new GenericFastJsonRedisSerializer();
        // 设置key和value的序列化规则
        redisTemplate.setKeySerializer(new GenericToStringSerializer<>(String.class));
        redisTemplate.setValueSerializer(genericFastJsonRedisSerializer);
        // 设置hashKey和hashValue的序列化规则
        redisTemplate.setHashKeySerializer(new GenericToStringSerializer<>(String.class));
        redisTemplate.setHashValueSerializer(genericFastJsonRedisSerializer);
        // 设置支持事物
        redisTemplate.setEnableTransactionSupport(Boolean.TRUE);
        redisTemplate.afterPropertiesSet();
        return redisTemplate;
    }

    @Bean
    public <V> RedisUtil<V> redisUtil(RedisTemplate<String, V> redisTemplate) {
        return new RedisUtil<>(redisTemplate);
    }

    @Bean
    public RedisLockUtil redisLockUtil(RedisTemplate<String, Object> redisTemplate) {
        return new RedisLockUtil(redisTemplate);
    }

    @Bean
    public RedisService redisService(RedisTemplate<String, Object> redisTemplate, RedisLockUtil redisLockUtil) {
        return new RedisService(redisTemplate, redisLockUtil);
    }

    @Bean
    public RedisSecurityUtil redisSecurityUtil(RedisUtil<User> redisUserUtil, RedisUtil<List<String>> redisListUtil) {
        return new RedisSecurityUtil(redisUserUtil, redisListUtil);
    }

    @Bean
    public RequestLimitAspect requestLimitAspect(RedisUtil<LimitMeta> redisUtil) {
        return new RequestLimitAspect(redisUtil);
    }

    /**
     * 过期监听(自定义类继承KeyExpirationEventMessageListener实现监听回调)
     * redis配置文件（redis.windows.conf）需要开启监听配置
     * set notify-keyspace-events Ex
     */
    @Bean
    RedisMessageListenerContainer container(RedisConnectionFactory redisConnectionFactory) {
        RedisMessageListenerContainer container = new RedisMessageListenerContainer();
        container.setConnectionFactory(redisConnectionFactory);
        return container;
    }
}
